package org.iabako.server.dao.report;

import org.iabako.shared.dto.FinancesBalance;
import org.iabako.shared.dto.ReportGenerationInputDTO;
import org.iabako.shared.entity.business.AbstractEntity;
import org.springframework.stereotype.Repository;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by jose on 27/01/15.
 */

@Repository("installmentReportDAO")
public class InstallmentReportDAO extends AbstractReportDAO {

    public Map<Object, FinancesBalance> getInstallmentsBy(ReportGenerationInputDTO reportGenerationInputDTO, Date dateAfter, Date dateBefore) {
        Map<Object, FinancesBalance> installmentsBy = new HashMap<Object, FinancesBalance>();

        if (new Date().compareTo(dateBefore) > 0) {
            //For historical view
            addPaymentsPayedAfterScheduledDate(reportGenerationInputDTO, installmentsBy, dateAfter, dateBefore);
        }

        //For historical and present view
        addInstallmentsByDate(reportGenerationInputDTO, installmentsBy, dateAfter, dateBefore);

        return installmentsBy;
    }

    private void addPaymentsPayedAfterScheduledDate(ReportGenerationInputDTO reportGenerationInputDTO, Map<Object, FinancesBalance> installmentsBy, Date dateAfter, Date dateBefore) {
        switch (reportGenerationInputDTO.getReportByEnum()) {
            case byClient:
                addPaymentsPayedAfterScheduledDateByClient(installmentsBy, dateAfter, dateBefore);
                break;
            case bySale:
                addPaymentsPayedAfterScheduledDateByClientBySale(installmentsBy, dateAfter, dateBefore);
                break;
        }
    }

    private void addPaymentsPayedAfterScheduledDateByClient(Map<Object, FinancesBalance> installmentsBy, Date dateAfter, Date dateBefore) {
        String query = "SELECT sale.client, SUM(p.amount) FROM Payment p join p.sale sale " +
                "WHERE p.scheduleDate >= :dateAfter AND p.scheduleDate < :dateBefore " +
                "AND p.date > :dateBefore " +
                "AND sale.enterprise IN (:enterprises) " +
                "GROUP BY sale.client";

        List<Object[]> result = (List<Object[]>) entityManager.createQuery(query).
                setParameter("dateAfter", dateAfter).setParameter("dateBefore", dateBefore).
                setParameter("enterprises", getSessionUser().getEnterprise().getVisibleEnterprisesFinancialData()).getResultList();

        addInstallmentToMapByEntity(installmentsBy, result, dateBefore, true);
    }

    private void addPaymentsPayedAfterScheduledDateByClientBySale(Map<Object, FinancesBalance> installmentsBy, Date dateAfter, Date dateBefore) {
        String query = "SELECT sale, SUM(p.amount) FROM Payment p join p.sale sale " +
                "WHERE p.scheduleDate >= :dateAfter AND p.scheduleDate < :dateBefore " +
                "AND p.date > :dateBefore " +
                "AND sale.enterprise IN (:enterprises) " +
                "GROUP BY sale";

        List<Object[]> result = (List<Object[]>) entityManager.createQuery(query).
                setParameter("dateAfter", dateAfter).setParameter("dateBefore", dateBefore).
                setParameter("enterprises", getSessionUser().getEnterprise().getVisibleEnterprisesFinancialData()).getResultList();

        addInstallmentToMapByEntity(installmentsBy, result, dateBefore, true);
    }

    private void addInstallmentsByDate(ReportGenerationInputDTO reportGenerationInputDTO, Map<Object, FinancesBalance> installmentsBy, Date dateAfter, Date dateBefore) {
        switch (reportGenerationInputDTO.getReportByEnum()) {
            case byClient:
                addInstallmentsByDateByClient(installmentsBy, dateAfter, dateBefore);
                break;
            case bySale:
                addInstallmentsByDateBySale(installmentsBy, dateAfter, dateBefore);
                break;
        }
    }

    private void addInstallmentsByDateByClient(Map<Object, FinancesBalance> installmentsBy, Date dateAfter, Date dateBefore) {
        String query = "SELECT sale.client, SUM(i.amount) FROM Installment i join i.sale sale " +
                "WHERE i.date >= :dateAfter AND i.date < :dateBefore " +
                "AND sale.enterprise IN (:enterprises) " +
                "GROUP BY sale.client";

        List<Object[]> result = (List<Object[]>) entityManager.createQuery(query).
                setParameter("dateAfter", dateAfter).setParameter("dateBefore", dateBefore).
                setParameter("enterprises", getSessionUser().getEnterprise().getVisibleEnterprisesFinancialData()).getResultList();

        addInstallmentToMapByEntity(installmentsBy, result, dateBefore, false);
    }

    private void addInstallmentsByDateBySale(Map<Object, FinancesBalance> installmentsBy, Date dateAfter, Date dateBefore) {
        String query = "SELECT sale, SUM(i.amount) FROM Installment i join i.sale sale " +
                "WHERE i.date >= :dateAfter AND i.date < :dateBefore " +
                "AND sale.enterprise IN (:enterprises) " +
                "GROUP BY sale";

        List<Object[]> result = (List<Object[]>) entityManager.createQuery(query).
                setParameter("dateAfter", dateAfter).setParameter("dateBefore", dateBefore).
                setParameter("enterprises", getSessionUser().getEnterprise().getVisibleEnterprisesFinancialData()).getResultList();

        addInstallmentToMapByEntity(installmentsBy, result, dateBefore, false);
    }
}
